home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************/
- /* Copyright(c) 1987, 1992 by BBN Systems and Technologies, */
- /* A Division of Bolt Beranek and Newman Inc. */
- /* */
- /* RDP implementation for 4.2/4.3bsd by Craig Partridge */
- /* */
- /* Permission to use, copy, modify, distribute, and sell this software */
- /* and its documentation for any purpose is hereby granted without fee, */
- /* provided that the above copyright notice and this permission appear */
- /* in all copies and in supporting documentation, and that the name of */
- /* Bolt Beranek and Newman Inc. not be used in advertising or */
- /* publicity pertaining to distribution of the software without */
- /* specific, written prior permission. BBN makes no representations */
- /* about the suitability of this software for any purposes. It is */
- /* provided "AS IS" without express or implied warranties. */
- /**************************************************************************/
-
- #include "../h/param.h"
- #include "../h/dir.h"
- #include "../h/user.h"
- #include "../h/mbuf.h"
- #include "../h/protosw.h"
- #include "../h/socket.h"
- #include "../h/socketvar.h"
- #include "../h/errno.h"
-
- #include "../net/if.h"
- #include "../net/route.h"
-
- #include "../netinet/in.h"
- #include "../netinet/in_pcb.h"
- #include "../netinet/in_systm.h"
- #include "../netinet/ip.h"
- #include "../netinet/ip_var.h"
- #include "../netinet/ip_icmp.h"
-
- #include "../netinet/rdp.h"
- #include "../netinet/rdp_var.h"
- #include "../netinet/rdp_ip.h"
- #include "../netinet/rdp_conf.h"
-
- extern u_short rdp_mtu;
-
- /**************************************************************************/
- /* send a data packet, if no data then send a NULL segment */
- /**************************************************************************/
-
- rdp_send(inp, m0)
- struct inpcb *inp;
- struct mbuf *m0;
- {
- register struct rdpip *ri;
- register struct mbuf *m;
- register u_short dlen;
- register int i;
- register struct rdpcb *rp = (struct rdpcb *)inp->inp_ppcb;
- struct rdpque *rq = rp->rp_rq;
- int flags;
- struct socket *so = inp->inp_socket;
- int error = 0;
-
- /* first, find out if we have a place for the packet */
- i = rp->rp_sndnxt - rp->rp_snduna;
-
- /* over running our buffer or remote buffer? */
- if ((i >= R_MAXSND) || (i >= (rp->rp_sndmax << 1)))
- {
- error = ENOBUFS;
- goto drop;
- }
-
- /* exceeding max in flight? */
- if (rp->rp_inflt >= rp->rp_maxinflt)
- panic("rdp_send: inflt");
-
- /* now, find the data length */
- for(dlen=0,m=m0; m != 0; m = m->m_next)
- dlen += m->m_len;
-
- if (dlen > rp->rp_sndbuf)
- {
- error = EMSGSIZE;
- goto drop;
- }
-
- /* grab header and set up */
- MGET(m,M_DONTWAIT,MT_HEADER);
- if (m == 0)
- {
- error = ENOBUFS;
- goto drop;
- }
-
- m->m_len = RI_SIZE;
- m->m_off = MMAXOFF - m->m_len;
- m->m_next = m0;
- bzero(mtod(m,caddr_t),m->m_len);
-
- ri = mtod(m,struct rdpip *);
-
- ri->ri_pr = IPPROTO_RDP;
- ri->ri_ttl = MAXTTL;
-
- ri->ri_src = inp->inp_laddr;
- ri->ri_dst = inp->inp_faddr;
- ri->ri_sport = inp->inp_lport;
- ri->ri_dport = inp->inp_fport;
-
- ri->ri_dlen = ntohs((u_short)dlen);
-
- if (dlen == 0)
- ri->ri_flags = RH_NULL | R_VERSION;
- else
- ri->ri_flags = R_VERSION;
-
- /* RFC: page 34 requires than an ACK always be present in data */
-
- ri->ri_flags |= RH_ACK;
- ri->ri_an = htonl(rp->rp_rcvcur);
-
- ri->ri_sn = htonl(rp->rp_sndnxt);
-
- /* don't swap bytes -- IP does it for IP header */
- ri->ri_len = (u_short)(RI_SIZE+dlen);
- ri->ri_hlen = (R_HDRSIZE >> 1);
-
- /* sum was zeroed by the bzero above */
- m->m_off += sizeof(struct ip);
- m->m_len -= sizeof(struct ip);
- ri->ri_sum = in_cksum(m,(int)dlen + R_HDRSIZE);
- m->m_off -= sizeof(struct ip);
- m->m_len += sizeof(struct ip);
-
- /* now, increment sndnxt and buffer socket level */
- rp->rp_sndnxt++;
- rp->rp_inflt++;
-
- /* statistics */
- rp->rp_datsegs++;
-
- /* if at max inflight or end of buffering, tell socket level to hold it */
- if ((rp->rp_inflt >= rp->rp_maxinflt) || (i == (R_MAXSND-1)) || (i == (rp->rp_sndmax << 1)-1))
- {
- so->so_snd.sb_cc = so->so_snd.sb_hiwat;
- rdp_info.rst_fullwin++;
- }
-
-
- /* stuff packet in queues */
- i += rq->rq_sndbase;
- i %= R_MAXSND;
-
- rq->rq_sndq[i] = m;
- rq->rq_sndtimer[i] = 0;
- rq->rq_retries[i] = 0;
-
- /* activity timer */
- rp->rp_timer = RT_NULLTIME;
-
- error = 0;
-
- /* copy packet */
- if ((m0 = m_copy(m,0,(int)M_COPYALL))==0)
- goto quit;
-
- rdp_info.rst_opackets++;
-
- flags = so->so_state & SS_PRIV;
- return(ip_output(m0,(struct mbuf *)0,&(inp->inp_route),flags));
-
- drop:
- if (m0 != 0)
- (void) m_freem(m0);
-
- quit:
- return(error);
- }
-
- /**************************************************************************/
- /* send an RST segment */
- /**************************************************************************/
-
- rdp_rst(inp,isack,seq,ack,route)
- struct inpcb *inp;
- int isack;
- u_long seq, ack;
- int route;
- {
- register struct rdpip *ri;
- register struct mbuf *m;
- int flags;
-
- m = m_getclr(M_DONTWAIT,MT_HEADER);
- if (m == 0)
- return(ENOBUFS);
-
- m->m_len = RI_SIZE;
- m->m_off = MMAXOFF - m->m_len;
- m->m_next = 0;
-
- ri = mtod(m,struct rdpip *);
-
- ri->ri_pr = IPPROTO_RDP;
- ri->ri_ttl = MAXTTL;
-
- ri->ri_src = inp->inp_laddr;
- ri->ri_dst = inp->inp_faddr;
- ri->ri_sport = inp->inp_lport;
- ri->ri_dport = inp->inp_fport;
- ri->ri_flags = RH_RST | R_VERSION;
-
- if (isack)
- {
- /* ack has special meanings -- don't fiddle with EACKs */
- ri->ri_flags |= RH_ACK;
- ri->ri_an = htonl(ack);
- }
-
- ri->ri_sn = htonl(seq);
-
- ri->ri_hlen = (R_HDRSIZE >> 1);
- /* IP worries about byte order */
- ri->ri_len = ((u_short)RI_SIZE);
-
- m->m_off += sizeof(struct ip);
- m->m_len -= sizeof(struct ip);
- ri->ri_sum = 0;
- ri->ri_sum = in_cksum(m,R_HDRSIZE);
- m->m_off -= sizeof(struct ip);
- m->m_len += sizeof(struct ip);
-
- flags = inp->inp_socket->so_state & SS_PRIV;
-
- rdp_info.rst_opackets++;
-
- if (route)
- return(ip_output(m,(struct mbuf *)0,&(inp->inp_route),flags));
-
- return(ip_output(m,(struct mbuf *)0,(struct route *)0,flags));
- }
-
- /**************************************************************************/
- /* send an ACK segment (with EACKs if supported) */
- /**************************************************************************/
-
- rdp_ack(inp,seq,ack)
- struct inpcb *inp;
- u_long seq, ack;
- {
- register struct rdpip *ri;
- register struct rdpcb *rp = (struct rdpcb *)inp->inp_ppcb;
- #ifdef EACK
- register struct rdpque *rq;
- register int i, j;
- register u_long *lp;
- u_long eack;
- #endif
- struct mbuf *m;
- unsigned len;
- int flags;
-
- MGET(m,M_DONTWAIT,MT_HEADER);
- if (m == 0)
- return(ENOBUFS);
-
- m->m_len = len = RI_SIZE;
- /* leave enough space for possible EACKs */
- m->m_off = MMAXOFF - (len + ((rp->rp_rcvhi - rp->rp_rcvcur) << 2));
- m->m_next = 0;
-
- ri = mtod(m,struct rdpip *);
-
- ri->ri_pr = IPPROTO_RDP;
- ri->ri_ttl = MAXTTL;
-
- ri->ri_src = inp->inp_laddr;
- ri->ri_dst = inp->inp_faddr;
- ri->ri_sport = inp->inp_lport;
- ri->ri_dport = inp->inp_fport;
-
- ri->ri_flags = R_VERSION | RH_ACK;
- ri->ri_an = htonl(ack);
-
- ri->ri_sn = htonl(seq);
-
- #ifdef EACK
- /* add EACKs and increment len */
- if ((i=(rp->rp_rcvhi - rp->rp_rcvcur)) != 0)
- {
- ri->ri_flags |= RH_EACK;
- lp = (u_long *)(((caddr_t)ri)+len);
-
- rq = rp->rp_rq;
- j = rq->rq_rcvbase;
- eack= rp->rp_rcvcur + 1;
-
- for(; i > 0; i--, eack++)
- {
- if (rq->rq_rcvq[j] != 0)
- {
- *lp++ = eack;
- len += sizeof(*lp);
- }
- if (++j == R_RCVWIN)
- j = 0;
- }
- m->m_len = len;
- }
- #endif
-
- ri->ri_len = ((u_short)len);
- len -= sizeof(struct ip);
- ri->ri_hlen = (len >> 1);
- ri->ri_dlen = 0;
-
- m->m_off += sizeof(struct ip);
- m->m_len -= sizeof(struct ip);
- ri->ri_sum = 0;
- ri->ri_sum = in_cksum(m,(int)len);
- m->m_off -= sizeof(struct ip);
- m->m_len += sizeof(struct ip);
-
- rdp_info.rst_opackets++;
-
- flags = inp->inp_socket->so_state & SS_PRIV;
- return(ip_output(m,(struct mbuf *)0,&(inp->inp_route),flags));
- }
-
- /**************************************************************************/
- /* send SYN segment */
- /**************************************************************************/
-
- rdp_syn(inp,isack,seq,ack)
- struct inpcb *inp;
- int isack;
- u_long seq, ack;
- {
- register struct rdpip *ri;
- register struct mbuf *m;
- register struct rdpsyn *rs;
- register int len;
- int flags;
-
- m = m_getclr(M_DONTWAIT,MT_HEADER);
- if (m == 0)
- return(ENOBUFS);
-
- m->m_len = len = RI_SIZE+R_VARSIZE;
- m->m_off = MMAXOFF - len;
- m->m_next = 0;
-
- ri = mtod(m,struct rdpip *);
- m->m_off += RI_SIZE;
- rs = mtod(m,struct rdpsyn *);
- m->m_off -= RI_SIZE;
-
- ri->ri_pr = IPPROTO_RDP;
- ri->ri_ttl = MAXTTL;
-
- ri->ri_src = inp->inp_laddr;
- ri->ri_dst = inp->inp_faddr;
- ri->ri_sport = inp->inp_lport;
- ri->ri_dport = inp->inp_fport;
- ri->ri_flags = RH_SYN | R_VERSION;
-
- if (isack)
- {
- /* ack has special meanings -- don't fiddle with EACKs */
- ri->ri_flags |= RH_ACK;
- ri->ri_an = htonl(ack);
- }
-
- rs->rs_mos = htons((u_short)R_RCVMAX);
- rs->rs_mss = htons(rdp_mtu);
-
- if (inp->inp_socket->so_type != SOCK_RDM)
- rs->rs_ff = RS_SDM;
-
- ri->ri_sn = htonl(seq);
-
- ri->ri_hlen = ((R_HDRSIZE+R_VARSIZE) >> 1);
- ri->ri_len = (u_short)len;
-
- m->m_off += sizeof(struct ip);
- m->m_len -= sizeof(struct ip);
- ri->ri_sum = 0;
- ri->ri_sum = in_cksum(m,len - sizeof(struct ip));
- m->m_off -= sizeof(struct ip);
- m->m_len += sizeof(struct ip);
-
- rdp_info.rst_opackets++;
-
- flags = inp->inp_socket->so_state & SS_PRIV;
- return(ip_output(m,(struct mbuf *)0,&(inp->inp_route),flags));
- }
-